例:
str1 = “1A2C3D4B56“;
str2 = “B1D23CA45B6A”
则最长公共子序列为”12C4B6”。
实现:动态规划(注意公共子序列中的每个字符可能不连续)
步骤一:str1的长度为M,str2的长度为N,生成大小为M*N的矩阵dp,dp[i][j]表示使用str[0,…i]与str[0,…j]的最长公共子序列的长度。
- dp第一列dp[0,..M-1][0]表示str1[0,…M-1]与str2[0]的最长公共子序列的长度。str2[0]只有一个字符,dp[i][0]的最大值为1,如果str1[i]==str2[0],则dp[i][0]=1,dp[i+1,..M-1][0]也为1.
- dp第一行dp[0][0,..N-1]与步骤1dp第一列同理。如果str1[0]==str2[j],则令dp[0][j]=1,dp[0][j+1,…N-1]也为1。
- 对非第一行第一列,dp[i][j]可能来自下面3种情况:
1)dp[i-1][j](类比第一列)
2)dp[i][j-1](类比第一行)
3)如果str1[i]==str2[j],还可能是dp[i-1][j-1]+1(即来自左上角)。比如str1=”ABCE”,str2=”ABCE”
因此最长公共子序列为:
dp[i][j]=max{dp[i-1][j], dp[i][j-1], dp[i-1][j-1]+1}
dp矩阵的右下角的值代表最长公共子序列的长度。
步骤二:获取具体的最长公共子序列
- 从矩阵的右下角开始向上、向左或向左上移动,同时用字符数组char[] rst表示最长公共子序列。
- 如果dp[i][j]大于dp[i][j-1]和dp[i-1][j],说明在计算dp[i][j]时,一定来自决策dp[i-1][j-1]+1,可以确定str1[i]=str2[j],并且这个字符一定属于最长公共子序列,把这个字符放进字符数组rst中,然后向左上方移动。
- 如果dp[i][j]=dp[i-1][j],可以向上方移动
- 如果dp[i][j]=dp[i][j-1],可以向左方移动
- 如果dp[i][j]同时等于dp[i-1][j]或dp[i][-1],向上或向左都可以移动。
1 | /* |
注意char类型数组转字符串String.valueOf(char[] chas)。ps:String真的是个“万能”类型!
1 | //Test |
输出:
1 | 由str1和str2组成的动态规划表dp: |